

import java.io.ByteArrayInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;


public class Controle {

	public HashMap<String,Integer> argFctPredefinie = new HashMap<String,Integer>();
	
	public HashMap<String,Method> methodFctPredefinie = new HashMap<String,Method>();
	
	private static HashMap<Object, ArrayList> transforme = new HashMap<Object, ArrayList>();
	
	public Controle() {
		argFctPredefinie.put("si", 2);
		argFctPredefinie.put("sinon", 3);
		argFctPredefinie.put("repete", 2);
		//argFctPredefinie.put("ecris", 1);
		argFctPredefinie.put("tantque", 2);
		argFctPredefinie.put("repetepour", 2);
		argFctPredefinie.put("exec", 1);
		
		Class c = Controle.class;
		Method[] tab = c.getMethods();
		
		Method  m;
		for (int i=0;i<tab.length;i++) {
			m = tab[i];	
			if(m.getName().equals("si"))
				methodFctPredefinie.put("si", m);			
			if(m.getName().equals("sinon"))
				methodFctPredefinie.put("sinon", m);			
			if(m.getName().equals("repete"))
				methodFctPredefinie.put("repete", m);	
			if(m.getName().equals("ecris"))
				methodFctPredefinie.put("ecris", m);			
			if(m.getName().equals("tantque"))
				methodFctPredefinie.put("tantque", m);			
			if(m.getName().equals("repetepour"))
				methodFctPredefinie.put("repetepour", m);			
			if(m.getName().equals("exec"))
				methodFctPredefinie.put("exec", m);
		}    
	};
	
	
	public static String listToString(ArrayList l){
		String list = "";
		
		for(int i=0; i<l.size();i++){
			if(l.get(i) instanceof ArrayList)
				list += "[" + listToString((ArrayList)l.get(i))+" ]";
			else
				list += l.get(i) +" ";
		}
		return list;
	}
	
	
	public static Object run(ArrayList<Object> list,  HashMap<String, Object> penv) throws ParseException, Exception{

    	Evaluation E = new Evaluation();
    	E.initEnv(penv);
    	
    	
        return E.evalCorps(listeTrans(list));
	}
	
	
	
	private static ArrayList<Object> listeTrans(ArrayList<Object> list) throws ParseException, Exception{
		ArrayList<Object> instruction;
		
		if(transforme.containsKey(list)){
			instruction = transforme.get(list);
		}
		else {
			byte[] b = listToString(list).getBytes();
			ByteArrayInputStream stream  = new ByteArrayInputStream(b);
			Trans parser = new Trans(stream);
		
			instruction = parser.run();
		
			transforme.put(list,instruction);
		}
		return instruction;
	}
	
	
	public static Object si(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		

		HashMap<String, Object> env = new HashMap<String, Object>();
		env.put("env_sup",penv);
		
		if((v.get(0) instanceof Boolean)  && v.get(1) instanceof ArrayList  && v.size()==2) {
			if ((Boolean)v.get(0)){
				
				return run((ArrayList)v.get(1),env);
			}
			else
				return false;
		}
		else
			return false;
	}
	
	
	public static Object sinon(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		
		HashMap<String, Object> env = new HashMap<String, Object>();
		
		env.put("env_sup",penv);
		
		if((v.get(0) instanceof Boolean)  && v.get(1) instanceof ArrayList  && v.size()==3) {
			if ((Boolean)v.get(0)) {
				
				return  run((ArrayList)v.get(1),env);
			}
			else {
				if(v.get(2) instanceof ArrayList) {
				
					return  run((ArrayList)v.get(2),env);
				}
				return false;
			}
		}
		else
			return false; 
	}
	
	
	
	public static Object repete(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		Object ret = null;
	
		
		HashMap<String, Object> env = new HashMap<String, Object>();
		env.put("env_sup",penv);
		
		if((v.get(0) instanceof Integer)  && v.get(1) instanceof ArrayList  && v.size()==2) {
			
			ArrayList<Object> instruction = listeTrans((ArrayList)v.get(1));
			
			Evaluation E = new Evaluation();
	    	E.initEnv(penv);
			
			for(int i=0; i<(Integer)v.get(0); i++)
				ret = E.evalCorps(instruction);
		}
		return ret;
	}
	
	
	
	
	public  static Object ecris(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		
		if(v.size()==1) {
			if(v.get(0) instanceof ArrayList) 
				System.out.println(listToString((ArrayList)v.get(0)));
			else
				System.out.println(v.get(0));
			
			return true;
		}
		else 
			return false;
	}
	
	
	
	public static Object tantque(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		Object ret = null;
		

		HashMap<String, Object> env = new HashMap<String, Object>();
		env.put("env_sup",penv);
		
		if(v.size() == 2 && v.get(0) instanceof ArrayList && v.get(1) instanceof ArrayList) {
			ArrayList<Object> instructionTest = listeTrans((ArrayList)v.get(0));
			
			ArrayList<Object> instruction = listeTrans((ArrayList)v.get(1));
	
			Evaluation E = new Evaluation();
	    	E.initEnv(penv);
			
			while((Boolean)E.evalCorps(instructionTest))
				ret = E.evalCorps(instruction);
		}
		return ret;
	}
	
	
	public static Object repetepour(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		ArrayList<Object> l = new ArrayList<Object>();
		Object ret = null;
		
		HashMap<String, Object> env = new HashMap<String, Object>();
		env.put("env_sup",penv);
		
		if(v.size() == 2 && v.get(0) instanceof ArrayList && v.get(1) instanceof ArrayList) {
			
			ArrayList<Object> list = listeTrans((ArrayList)v.get(0));
			ArrayList<Object> instruction = listeTrans((ArrayList)v.get(1));
	        
			Evaluation E = new Evaluation();
	    	E.initEnv(penv);
	    	
	    	l = (ArrayList)E.evalListe(list);
			
			if(l.size() == 3 || l.size() == 4){
				int borne = (Integer)l.get(2);
				String interateur = (String)l.get(0);
			
				int pas = 1; 
				
				if(l.size() == 4)
					pas = (Integer)l.get(3);
				
				for(int n = (Integer)l.get(1); n<borne; n+=pas) {
					penv.put(interateur,n);
					ret = E.evalCorps(instruction);
				}
				penv.remove(interateur);
			}	
		}
		return ret;	
	}
	
	
	public static Object exec(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
	
		if(v.size() == 1 && v.get(0) instanceof ArrayList ) 
			return run((ArrayList)v.get(0),penv);
		else
			return null;
	}
		
}
